#include "mpitracer_fortran.h"

void mpi_init_(MPI_Fint *ierr){
    static MPI_INIT_FORTRAN old_fn= NULL;
    fortran_handle = dlopen("libmpi_mpifh.so", RTLD_LAZY);
    old_fn= (MPI_INIT_FORTRAN)dlsym(fortran_handle, "MPI_INIT");
    init_mpitracer();
    old_fn(ierr);
    attach_tracer();
    init_tracer_statistician();
}

void mpi_finalize_(MPI_Fint *ierr){
    static MPI_FINALIZE_FORTRAN old_fn= NULL;
    //int ret=0;
    char log_file[256];
    FILE* fp;
    int i,offset;
    Ignore_all_fn();
    MPI_Barrier(pMPI_comm_world);
    tracer_exit_flag=1;
    if(writer_enable){
        writer_exit_flag=1;
        pthread_join(tid,NULL);
    }else{
        sprintf(log_file,"%s/%s_%d.log",log_dir,log_prefix,tracer_rank);
        fp=fopen(log_file,"w");
        fprintf( fp, "%lf\t%u\n", rank_start_ts, init_pid);
        fprintf( fp, "%9s\t%25s\t%17s\t%9s\t%10s\t%10s\t%7s\t%7s\t%7s\t%7s\t%7s\t%9s\t%8s\t%8s\t%7s\t%9s\t%8s\t%8s\t%7s\n","ID","MPI_TYPE","TimeStamp","Call","Elapse","Comm","Tag","SRC","DST","GSRC","GDST","SCount","SBuf_B","SLen_B","SBW_Gbps","RCount","RBuf_B","RLen_B","RBW_Gbps");
        offset = trace_index%max_trace_num;
        for(i=offset;i<max_trace_num;i++){
            print_log(fp,&probe_log[i]);
        }
        for(i=0;i<offset;i++){
            print_log(fp,&probe_log[i]);
        }
        fclose(fp);
    }
    if(mt_flag){
        pthread_mutex_destroy( &log_mutex ) ;
    }
    if(trace_reducer_enable){
        trace_reducer_process();
    }
    #ifdef DEBUG
    view_htable(request_htable);
    #endif
    free(probe_log);
    free_tracer_statistician();
    if(0==tracer_rank){
        printf("MPITRACER\tPlease check files of %s/%s_<rank_id>.log on each node\n",log_dir,log_prefix);
        printf("MPITRACER\tRecord %ld traces of rank 0\n",(trace_index+1));
        if(issue_found_flag){
            printf("MPITRACER\tProgram issues found that using Non-blocking, check the traces where elapse time is 999.0\n");
        }
        if(trace_reducer_enable){
            printf("MPITRACER\tTrace summary saved to %s:%s\n",root_hostname,reducer_log_file);
        }
    }
    if (comm_index) {
        char comm_file[256];
        sprintf(comm_file,"%s/%s_comm_%d.log",log_dir,log_prefix,tracer_rank);
        fp=fopen(comm_file,"w");
        fprintf(fp,"%10s %7s\n","COMM","GRANK");
            int j,tmp_idx;
            int grank;
            group_node_t *g=NULL;
            int comm_size = -1;
            MPI_Comm comm;
            for (tmp_idx=0;tmp_idx<comm_index;tmp_idx++){
                comm=STORE_COMM[tmp_idx];
                #ifdef USEINTELMPI
                fprintf(fp,"%10x    ",comm);
                g=hash_find_obj((unsigned int)comm,group_htable,group_node_t);
                #else
                fprintf(fp,"%10p    ",comm);
                g=hash_find_obj((long)comm,group_htable,group_node_t);
                #endif                
                if(!g){
                    printf("error:can not find correct group_node_t struct.\n");
                    return;
                }
                comm_size=g->num;
                for (j=0;j<comm_size;j++){
                    grank = g->map[j];
                    if (j!=comm_size-1){
                        fprintf(fp,"%d,",grank);
                    }else{
                        fprintf(fp,"%d\n",grank);
                    }
                }
            }
            fclose(fp);
    } 
    old_fn= (MPI_FINALIZE_FORTRAN)dlsym(fortran_handle, "MPI_FINALIZE");
    old_fn(ierr);
    dlclose(fortran_handle);
    //return ret;
}

void mpi_send_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype,
                MPI_Fint *dest_FORTRAN, MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *ierr)
{
    //int ret;
    int type=type_send;
    double start,end;
    int idx=-1;
    int count = -1;
    trace_log_t* log;
    MPI_SEND_FORTRAN fn=get_trace_type_fortran_fn(type);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int dest = (*dest_FORTRAN);
    int tag = (*tag_FORTRAN);
    int size = 0;
    MPI_Datatype c_type = PMPI_Type_f2c(*datatype);
    MPI_Type_size(c_type,&size);
    count = (*count_FORTRAN);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)) {
        //return fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
        fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
        return;
    }
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->peer=dest;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=count;
    log->sdatatype_size=size;
    log->tag=tag;
    trace_index++;
    MT_UNLOCK()
    // return ret;
}

void mpi_isend_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype, MPI_Fint *dest_FORTRAN, 
     MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN, MPI_Fint *ierr)
{
    //int ret;
    int type=type_isend;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_ISEND_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    MPI_Request request;
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int dest = (*dest_FORTRAN);
    int tag = (*tag_FORTRAN);
    int count = (*count_FORTRAN);
    MPI_Datatype c_type = PMPI_Type_f2c(*datatype);
    MPI_Type_size(c_type,&size);
    
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)) {
        fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
      return ;
    }
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->peer=dest;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=count;
    log->sdatatype_size=size;
    log->tag=tag;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
    //return ret;
}

void mpi_bsend_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype, 
    MPI_Fint *dest_FORTRAN, MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int type=type_bsend;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_BSEND_FORTRAN fn=get_trace_type_fortran_fn(type);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int dest = (*dest_FORTRAN);
    int tag = (*tag_FORTRAN);
    int size = 0;
    MPI_Datatype c_type = PMPI_Type_f2c(*datatype);
    MPI_Type_size(c_type,&size);
    int count = (*count_FORTRAN);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
        return ;
    }
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->peer=dest;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=count;
    log->sdatatype_size=size;
    log->tag=tag;
    trace_index++;
    MT_UNLOCK()
}

void mpi_ibsend_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype,
		  MPI_Fint *dest_FORTRAN, MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN,
		  MPI_Fint *request_FORTRAN, MPI_Fint *ierr){
    int type=type_ibsend;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_IBSEND_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    MPI_Request request ;
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int dest = (*dest_FORTRAN);
    int tag = (*tag_FORTRAN);
    int count = (*count_FORTRAN);
    MPI_Datatype c_type = PMPI_Type_f2c(*datatype);
    MPI_Type_size(c_type,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return;
    }
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->peer=dest;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=count;
    log->sdatatype_size=size;
    log->tag=tag;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK();
}

void mpi_ssend_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype,
		 MPI_Fint *dest_FORTRAN, MPI_Fint *tag_FORTRAN,
		 MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int type=type_ssend;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_SSEND_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int dest = (*dest_FORTRAN);
    int tag = (*tag_FORTRAN);
    int count = (*count_FORTRAN);
    MPI_Datatype c_type = PMPI_Type_f2c(*datatype);
    MPI_Type_size(c_type,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)) {
        return fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
    }
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->peer=dest;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=count;
    log->sdatatype_size=size;
    log->tag=tag;
    trace_index++;
    MT_UNLOCK()
}

void mpi_issend_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype,
    MPI_Fint *dest_FORTRAN, MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN, 
    MPI_Fint *request_FORTRAN, MPI_Fint *ierr){
    int type=type_issend;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_ISSEND_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    MPI_Request request ;
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int dest = (*dest_FORTRAN);
    int tag = (*tag_FORTRAN);
    int count = (*count_FORTRAN);
    MPI_Datatype c_type = PMPI_Type_f2c(*datatype);
    MPI_Type_size(c_type,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
         fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
         return ;
    }
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->peer=dest;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=count;
    log->sdatatype_size=size;
    log->tag=tag;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

void mpi_rsend_(char *ibuf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype,
		 MPI_Fint *dest_FORTRAN, MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int type=type_rsend;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_RSEND_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int dest = (*dest_FORTRAN);
    int tag = (*tag_FORTRAN);
    int count = (*count_FORTRAN);
    MPI_Datatype c_type = PMPI_Type_f2c(*datatype);
    MPI_Type_size(c_type,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(ibuf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
        return ;
    }
    start=timer_fn();
    fn(ibuf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->peer=dest;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=count;
    log->sdatatype_size=size;
    log->tag=tag;
    trace_index++;
    MT_UNLOCK()
}

void mpi_irsend_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype, 
      MPI_Fint *dest_FORTRAN, MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN, MPI_Fint *ierr){
    int type=type_irsend;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_IRSEND_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    MPI_Request request ;
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int dest = (*dest_FORTRAN);
    int tag = (*tag_FORTRAN);
    int count = (*count_FORTRAN);
    MPI_Datatype c_type = PMPI_Type_f2c(*datatype);
    MPI_Type_size(c_type,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return;
    }
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype,dest_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->peer=dest;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=count;
    log->sdatatype_size=size;
    log->tag=tag;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

void mpi_recv_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype_FORTRAN,
                MPI_Fint *source_FORTRAN, MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN,
                MPI_Fint *status_FORTRAN, MPI_Fint *ierr){
    int type=type_recv;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_RECV_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    int tmp_count=0;
    //int count = OMPI_FINT_2_INT(*count_FORTRAN);
    int count = (*count_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int source = (*source_FORTRAN);
    int tag = (*tag_FORTRAN);
    
    MPI_Datatype datatype = PMPI_Type_f2c(*datatype_FORTRAN);
    MPI_Type_size(datatype,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(buf,count_FORTRAN,datatype_FORTRAN,source_FORTRAN,tag_FORTRAN,comm_FORTRAN,status_FORTRAN,ierr);
        return ;
    } 
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype_FORTRAN,source_FORTRAN,tag_FORTRAN,comm_FORTRAN,status_FORTRAN,ierr);
    end=timer_fn();
    MPI_Status *status = (MPI_Status *) status_FORTRAN ;
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    if(status!=mpi_status_ignore){
        log->peer=status->MPI_SOURCE;
        log->gpeer=rank2global(log->peer,comm);
        log->tag=status->MPI_TAG;
        MPI_Get_count(status,datatype,&tmp_count);
        log->rcount=tmp_count;
    }else{
        log->rcount=count;
        log->peer=source;
        log->gpeer=rank2global(log->peer,comm);
        log->tag=tag;
    }
    log->comm=comm;
    log->rdatatype_size=size;
    trace_index++;
    MT_UNLOCK()
}

void mpi_irecv_(char *buf, MPI_Fint *count_FORTRAN, MPI_Fint *datatype_FORTRAN,
		 MPI_Fint *source_FORTRAN, MPI_Fint *tag_FORTRAN, MPI_Fint *comm_FORTRAN,
		 MPI_Fint *request_FORTRAN, MPI_Fint *ierr){
    int type=type_irecv;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_IRECV_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    int count = (*count_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int source = (*source_FORTRAN);
    int tag = (*tag_FORTRAN);
    MPI_Request request ;
   
    MPI_Datatype datatype = PMPI_Type_f2c(*datatype_FORTRAN);
    MPI_Type_size(datatype,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
         fn(buf,count_FORTRAN,datatype_FORTRAN,source_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
         return ;
    } 
    start=timer_fn();
    fn(buf,count_FORTRAN,datatype_FORTRAN,source_FORTRAN,tag_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->rcount=count;
    log->peer=source;
    log->gpeer=rank2global(log->peer,comm);
    log->tag=tag;
    log->comm=comm;
    log->rdatatype_size=size;
    log->private=datatype;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

// MPI_Recv_init

void mpi_wait_(MPI_Fint *request_FORTRAN, MPI_Fint *status_FORTRAN, MPI_Fint *ierr){
    int type=type_wait;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_WAIT_FORTRAN fn=get_trace_type_fortran_fn(type);
    MPI_Request request;
    MPI_Status *status  ;
    start=timer_fn();
    fn(request_FORTRAN,status_FORTRAN,ierr);
    end=timer_fn();
    status = (MPI_Status *) status_FORTRAN ;
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    update_end_ts_of_cached_logs(1,&request,status,end);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)){
        MT_UNLOCK()
        return ;
    }
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->scount=1;
    trace_index++;
    MT_UNLOCK()
}

void mpi_waitall_(MPI_Fint *count_FORTRAN, MPI_Fint *array_of_requests_FORTRAN,
		   MPI_Fint *array_of_statuses_FORTRAN, MPI_Fint *ierr){
    int idx=-1;
    int type=type_waitall;
    double start,end;
    trace_log_t* log;
    MPI_WAITALL_FORTRAN fn=get_trace_type_fortran_fn(type);
    int count = (*count_FORTRAN);
    MPI_Request *array_of_requests = (MPI_Request *) malloc(count *
                   (sizeof(MPI_Request)));
    MPI_Status *array_of_statuses = (MPI_Status *) malloc(count *
                   (sizeof(MPI_Status))) ;
    //array_of_statuses = (MPI_Status*) (array_of_requests_FORTRAN + (*count));
     
    start=timer_fn();

    fn(count_FORTRAN,array_of_requests_FORTRAN,array_of_statuses_FORTRAN,ierr);
    end=timer_fn();
    for (int i = 0; i < count; ++i) {
        array_of_requests[i] = PMPI_Request_f2c(array_of_requests_FORTRAN[i]);
    }
     for (int i = 0; i < count; ++i) {
        PMPI_Status_f2c(&array_of_statuses_FORTRAN[i], &array_of_statuses[i]);
    }
    
    MT_LOCK()
    update_end_ts_of_cached_logs(count,array_of_requests,array_of_statuses,end);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)) {
        MT_UNLOCK()
        return ;
    }
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->scount=count;
    trace_index++;
    MT_UNLOCK()
}

void mpi_test_(MPI_Fint *request_FORTRAN, MPI_Fint *flag,
                MPI_Fint *status_FORTRAN, MPI_Fint *ierr){
    int type=type_test;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_TEST_FORTRAN fn=get_trace_type_fortran_fn(type);
    MPI_Request request;
    MPI_Status *status ;
    start=timer_fn();
    fn(request_FORTRAN,flag,status_FORTRAN,ierr);
    status = (MPI_Status *) status_FORTRAN ;
    request = PMPI_Request_f2c(*request_FORTRAN);
    if(*flag==false){
        return;
    }
    end=timer_fn();
    MT_LOCK()
    update_end_ts_of_cached_logs(1,&request,status,end);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)) {
        MT_UNLOCK()
        return;
    }
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->scount=1;
    trace_index++;
    MT_UNLOCK()
}

void mpi_testall_(MPI_Fint *count_FORTRAN, MPI_Fint *array_of_requests_FORTRAN, MPI_Fint *flag, 
            MPI_Fint *array_of_statuses_FORTRAN, MPI_Fint *ierr){
    int type=type_testall;
    double start,end;
    int idx=-1;
    trace_log_t* log;
    MPI_TESTALL_FORTRAN fn=get_trace_type_fortran_fn(type);
    int count = (*count_FORTRAN);
    MPI_Request *array_of_requests = (MPI_Request *) malloc(count *
                   (sizeof(MPI_Request)));
    MPI_Status *array_of_statuses = (MPI_Status *) malloc(count *
                   (sizeof(MPI_Status))) ;
    start=timer_fn();
    fn(count_FORTRAN,array_of_requests_FORTRAN,flag,array_of_statuses_FORTRAN,ierr);
    if(*flag==false){
        return ;
    }
    for (int i = 0; i < count; ++i) {
        array_of_requests[i] = PMPI_Request_f2c(array_of_requests_FORTRAN[i]);
    }
    for (int i = 0; i < count; ++i) {
        PMPI_Status_f2c(&array_of_statuses_FORTRAN[i], &array_of_statuses[i]);
    }
    end=timer_fn();
    MT_LOCK()
    update_end_ts_of_cached_logs(count,array_of_requests,array_of_statuses,end);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)) {
        MT_UNLOCK()
        return;
    }
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->scount=count;
    trace_index++;
    MT_UNLOCK()
}

void mpi_alltoall_(char *sendbuf, MPI_Fint *sendcount_FORTRAN, MPI_Fint *sendtype_FORTRAN,
		    char *recvbuf, MPI_Fint *recvcount_FORTRAN, MPI_Fint *recvtype_FORTRAN,
		    MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int idx=-1;
    int type=type_alltoall;
    double start,end;
    trace_log_t* log;
    MPI_ALLTOALL_FORTRAN fn=get_trace_type_fortran_fn(type);
    int ssize=0;
    int rsize=0;
    int sendcount = (*sendcount_FORTRAN);
    int recvcount = (*recvcount_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Datatype sendtype = PMPI_Type_f2c(*sendtype_FORTRAN);
    MPI_Datatype recvtype = PMPI_Type_f2c(*recvtype_FORTRAN);
    MPI_Type_size(sendtype,&ssize);
    MPI_Type_size(recvtype,&rsize);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&(log_threshold>recvcount*rsize||log_threshold>sendcount*ssize))){
        fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,comm_FORTRAN,ierr);
        return;
    }
    start=timer_fn();
    fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->scount=sendcount;
    log->sdatatype_size=ssize;
    log->rcount=recvcount;
    log->rdatatype_size=rsize;
    trace_index++;
    MT_UNLOCK()
}

// MPI_Alltoallv

void mpi_ialltoall_(char *sendbuf, MPI_Fint *sendcount_FORTRAN, MPI_Fint *sendtype_FORTRAN,
                      char *recvbuf, MPI_Fint *recvcount_FORTRAN, MPI_Fint *recvtype_FORTRAN,
                      MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN, MPI_Fint *ierr){
    int idx=-1;
    int type=type_ialltoall;
    double start,end;
    trace_log_t* log;
    MPI_IALLTOALL_FORTRAN fn=get_trace_type_fortran_fn(type);
    int sendcount = (*sendcount_FORTRAN);
    int recvcount = (*recvcount_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Datatype sendtype = PMPI_Type_f2c(*sendtype_FORTRAN);
    MPI_Datatype recvtype = PMPI_Type_f2c(*recvtype_FORTRAN);
    int ssize=0;
    int rsize=0;
    MPI_Request request;
    MPI_Type_size(sendtype,&ssize);
    MPI_Type_size(recvtype,&rsize);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&(log_threshold>recvcount*rsize||log_threshold>sendcount*ssize))){
        fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return;
    }
    start=timer_fn();
    fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->scount=sendcount;
    log->sdatatype_size=ssize;
    log->rcount=recvcount;
    log->rdatatype_size=rsize;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

// MPI_Ialltoallv
// MPI_Ineighbor_alltoallv

void mpi_bcast_(char *buffer, MPI_Fint *count_FORTRAN, MPI_Fint *datatype_FORTRAN,
		 MPI_Fint *root_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int idx=-1;
    int type=type_bcast;
    double start,end;
    trace_log_t* log;
    MPI_BCAST_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    MPI_Datatype datatype = PMPI_Type_f2c(*datatype_FORTRAN);
    int count = (*count_FORTRAN);
    int root = (*root_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Type_size(datatype,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(buffer,count_FORTRAN,datatype_FORTRAN,root_FORTRAN,comm_FORTRAN,ierr);
        return;
    }
    start=timer_fn();
    fn(buffer,count_FORTRAN,datatype_FORTRAN,root_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->peer=root;
    log->gpeer=rank2global(log->peer,comm);
    if(root==tracer_rank){
        log->scount=count;
        log->sdatatype_size=size;
        log->rcount=0;
        log->rdatatype_size=0;
    }else{
        log->rcount=count;
        log->rdatatype_size=size;
        log->scount=0;
        log->sdatatype_size=0;
    }
    trace_index++;
    MT_UNLOCK()
}

void mpi_ibcast_(char *buffer, MPI_Fint *count_FORTRAN, MPI_Fint *datatype_FORTRAN,
                   MPI_Fint *root_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN,
                   MPI_Fint *ierr){
    int type=type_ibcast;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_IBCAST_FORTRAN fn=get_trace_type_fortran_fn(type);
    int size=0;
    MPI_Request request;
    MPI_Datatype datatype = PMPI_Type_f2c(*datatype_FORTRAN);
    int count = (*count_FORTRAN);
    int root = (*root_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Type_size(datatype,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(buffer,count_FORTRAN,datatype_FORTRAN,root_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return;
    } 
    start=timer_fn();
    fn(buffer,count_FORTRAN,datatype_FORTRAN,root_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->peer=root;
    log->gpeer=rank2global(log->peer,comm);
    if(root==tracer_rank){
        log->scount=count;
        log->sdatatype_size=size;
        log->rcount=0;
        log->rdatatype_size=0;
    }else{
        log->rcount=count;
        log->rdatatype_size=size;
        log->scount=0;
        log->sdatatype_size=0;
    }
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

void mpi_reduce_(char *sendbuf, char *recvbuf, MPI_Fint *count_FORTRAN,
		  MPI_Fint *datatype_FORTRAN, MPI_Fint *op_FORTRAN,
		  MPI_Fint *root_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int type=type_reduce;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_REDUCE_FORTRAN fn=get_trace_type_fortran_fn(type);
    int count = (*count_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Datatype datatype = PMPI_Type_f2c(*datatype_FORTRAN);
    int root = (*root_FORTRAN);
    int size=0;
    MPI_Type_size(datatype,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)) {
        fn(sendbuf,recvbuf,count_FORTRAN,datatype_FORTRAN,op_FORTRAN,root_FORTRAN,comm_FORTRAN,ierr);
        return ;
    }
    start=timer_fn();
    fn(sendbuf,recvbuf,count_FORTRAN,datatype_FORTRAN,op_FORTRAN,root_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->peer=root;
    log->gpeer=rank2global(log->peer,comm);
    if(root==tracer_rank){
        log->rcount=count;
        log->rdatatype_size=size;
        log->scount=0;
        log->sdatatype_size=0;
    }else{
        log->scount=count;
        log->sdatatype_size=size;
        log->rcount=0;
        log->rdatatype_size=0;
    }
    trace_index++;
    MT_UNLOCK()
}

void mpi_ireduce_(char *sendbuf, char *recvbuf, MPI_Fint *count_FORTRAN,
                    MPI_Fint *datatype_FORTRAN, MPI_Fint *op_FORTRAN,
                    MPI_Fint *root_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN,
                    MPI_Fint *ierr){
    int type=type_ireduce;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_IREDUCE_FORTRAN fn=get_trace_type_fortran_fn(type);
    int count = (*count_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Datatype datatype = PMPI_Type_f2c(*datatype_FORTRAN);
    int root = (*root_FORTRAN);
    MPI_Request request;
    int size=0;
    MPI_Type_size(datatype,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)) { 
        fn(sendbuf,recvbuf,count_FORTRAN,datatype_FORTRAN,op_FORTRAN,root_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return ;
    }
    start=timer_fn();
    fn(sendbuf,recvbuf,count_FORTRAN,datatype_FORTRAN,op_FORTRAN,root_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->peer=root;
    log->gpeer=rank2global(log->peer,comm);
    if(root==tracer_rank){
        log->rcount=count;
        log->rdatatype_size=size;
        log->scount=0;
        log->sdatatype_size=0;
    }else{
        log->scount=count;
        log->sdatatype_size=size;
        log->rcount=0;
        log->rdatatype_size=0;
    }
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

void mpi_allreduce_(char *sendbuf, char *recvbuf, MPI_Fint *count_FORTRAN,
		     MPI_Fint *datatype_FORTRAN, MPI_Fint *op_FORTRAN, MPI_Fint *comm_FORTRAN,
		     MPI_Fint *ierr){
    int type=type_allreduce;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_ALLREDUCE_FORTRAN fn=get_trace_type_fortran_fn(type);
    int count = (*count_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Datatype datatype = PMPI_Type_f2c(*datatype_FORTRAN);
    int size=0;
    MPI_Type_size(datatype,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(sendbuf,recvbuf,count_FORTRAN,datatype_FORTRAN,op_FORTRAN,comm_FORTRAN,ierr);
        return;
    } 
    start=timer_fn();
    fn(sendbuf,recvbuf,count_FORTRAN,datatype_FORTRAN,op_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->rcount=count;
    log->scount=count;
    log->rdatatype_size=size;
    log->sdatatype_size=size;
    trace_index++;
    MT_UNLOCK()
}

void mpi_iallreduce_(char *sendbuf, char *recvbuf, MPI_Fint *count_FORTRAN,
                       MPI_Fint *datatype_FORTRAN, MPI_Fint *op_FORTRAN, MPI_Fint *comm_FORTRAN,
                       MPI_Fint *request_FORTRAN, MPI_Fint *ierr){
    int type=type_iallreduce;
    int idx=-1;
    double start,end;
    int size=0;
    trace_log_t* log;
    MPI_IALLREDUCE_FORTRAN fn=get_trace_type_fortran_fn(type);
    int count = (*count_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Datatype datatype = PMPI_Type_f2c(*datatype_FORTRAN);
    MPI_Request request;
    MPI_Type_size(datatype,&size);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&log_threshold>count*size)){
        fn(sendbuf,recvbuf,count_FORTRAN,datatype_FORTRAN,op_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return;
    }  
    start=timer_fn();
    fn(sendbuf,recvbuf,count_FORTRAN,datatype_FORTRAN,op_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->rcount=count;
    log->scount=count;
    log->rdatatype_size=size;
    log->sdatatype_size=size;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

void mpi_barrier_(MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int type=type_barrier;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_BARRIER_FORTRAN fn=get_trace_type_fortran_fn(type);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)){
        fn(comm_FORTRAN,ierr);
        return ;
    }
     
    start=timer_fn();
    fn(comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    trace_index++;
    MT_UNLOCK()
}

void mpi_ibarrier_(MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN, MPI_Fint *ierr){
    int type=type_ibarrier;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_IBARRIER_FORTRAN fn=get_trace_type_fortran_fn(type);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Request request;
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)){
        fn(comm_FORTRAN,request_FORTRAN,ierr);
        return;
    }  
    start=timer_fn();
    fn(comm_FORTRAN,request_FORTRAN,ierr);
    request = PMPI_Request_f2c(*request_FORTRAN);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

void mpi_comm_split_(MPI_Fint *comm, MPI_Fint *color, MPI_Fint *key,
		      MPI_Fint *newcomm_FORTRAN, MPI_Fint *ierr){
    MPI_COMM_SPLIT_FORTRAN old_fn=NULL;
    int type=type_comm_split;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    fortran_handle = dlopen("libmpi_mpifh.so", RTLD_LAZY);
    old_fn= (MPI_COMM_SPLIT_FORTRAN)dlsym(fortran_handle, "MPI_COMM_SPLIT");
    start=timer_fn();
    old_fn(comm,color,key,newcomm_FORTRAN,ierr);
    end=timer_fn();
    MPI_Comm newcomm = PMPI_Comm_f2c(*newcomm_FORTRAN);
    update_group(newcomm);

    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)) return ;
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=newcomm;
    trace_index++;
	if(newcomm != mpi_comm_null){
        STORE_COMM[comm_index]=newcomm;
        comm_index++;
    }
    MT_UNLOCK()
}

// MPI_Comm_split_type

void mpi_comm_dup_(MPI_Fint *comm, MPI_Fint *newcomm_FORTRAN, MPI_Fint *ierr){
    MPI_COMM_DUP_FORTRAN old_fn=NULL;
    int type=type_comm_dup;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    fortran_handle = dlopen("libmpi_mpifh.so", RTLD_LAZY);
    old_fn= (MPI_COMM_DUP_FORTRAN)dlsym(fortran_handle, "MPI_COMM_DUP");
    start=timer_fn();
    old_fn(comm,newcomm_FORTRAN,ierr);
    end=timer_fn();
    MPI_Comm newcomm = PMPI_Comm_f2c(*newcomm_FORTRAN);
    update_group(newcomm);

    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)) return;
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=newcomm;
    trace_index++;
	if(newcomm != mpi_comm_null){
        STORE_COMM[comm_index]=newcomm;
        comm_index++;
    }
    MT_UNLOCK()
}

void mpi_comm_create_(MPI_Fint *comm, MPI_Fint *group, MPI_Fint *newcomm_FORTRAN, MPI_Fint *ierr){
    MPI_COMM_CREATE_FORTRAN old_fn=NULL;
    int type=type_comm_create;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    fortran_handle = dlopen("libmpi_mpifh.so", RTLD_LAZY);
    old_fn= (MPI_COMM_CREATE_FORTRAN)dlsym(fortran_handle, "MPI_COMM_CREATE");
    MPI_Comm newcomm;
    start=timer_fn();
    old_fn(comm,group,newcomm_FORTRAN,ierr);
    newcomm = PMPI_Comm_f2c(*newcomm_FORTRAN);
    end=timer_fn();
    update_group(newcomm);

    if((TRACE_IGNORE_LIST[type])||(log_threshold>0)) return;
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=newcomm;
    trace_index++;
	if(newcomm != mpi_comm_null){
        STORE_COMM[comm_index]=newcomm;
        comm_index++;
    }
    MT_UNLOCK()
}
// MPI_Cart_create
// MPI_Graph_create
// MPI_Dist_graph_create_adjacent
// MPI_Cart_sub
// MPI_Intercomm_create
// MPI_Intercomm_merge

void mpi_gather_(char *sendbuf, MPI_Fint *sendcount_FORTRAN, MPI_Fint *sendtype_FORTRAN,
		  char *recvbuf, MPI_Fint *recvcount_FORTRAN, MPI_Fint *recvtype_FORTRAN,
		  MPI_Fint *root_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int type=type_gather;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_GATHER_FORTRAN fn=get_trace_type_fortran_fn(type);
    int sendcount = (*sendcount_FORTRAN);
    int recvcount = (*recvcount_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int root = (*root_FORTRAN);
    MPI_Datatype sendtype = PMPI_Type_f2c(*sendtype_FORTRAN);
    MPI_Datatype recvtype = PMPI_Type_f2c(*recvtype_FORTRAN);
    int ssize=0;
    int rsize=0;
    MPI_Type_size(sendtype,&ssize);
    MPI_Type_size(recvtype,&rsize);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&(log_threshold>recvcount*rsize||log_threshold>sendcount*ssize))){
        fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,root_FORTRAN,comm_FORTRAN,ierr);
        return;
    } 
    start=timer_fn();
    fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,root_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->peer=root;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=sendcount;
    log->sdatatype_size=ssize;
    log->rcount=recvcount;
    log->rdatatype_size=rsize;
    trace_index++;
    MT_UNLOCK()
}

// MPI_Gatherv

void mpi_igather_(char *sendbuf, MPI_Fint *sendcount_FORTRAN, MPI_Fint *sendtype_FORTRAN,
                    char *recvbuf, MPI_Fint *recvcount_FORTRAN, MPI_Fint *recvtype_FORTRAN,
                    MPI_Fint *root_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN,
                    MPI_Fint *ierr){
    int type=type_igather;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_IGATHER_FORTRAN fn=get_trace_type_fortran_fn(type);
    int sendcount = (*sendcount_FORTRAN);
    int recvcount = (*recvcount_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int root = (*root_FORTRAN);
    MPI_Datatype sendtype = PMPI_Type_f2c(*sendtype_FORTRAN);
    MPI_Datatype recvtype = PMPI_Type_f2c(*recvtype_FORTRAN);
    MPI_Request request;
    int ssize=0;
    int rsize=0;
    MPI_Type_size(sendtype,&ssize);
    MPI_Type_size(recvtype,&rsize);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&(log_threshold>recvcount*rsize||log_threshold>sendcount*ssize))){
        fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,root_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return;
    } 
    start=timer_fn();
    fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,root_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->peer=root;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=sendcount;
    log->sdatatype_size=ssize;
    log->rcount=recvcount;
    log->rdatatype_size=rsize;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

// MPI_Igatherv

void mpi_allgather_(char *sendbuf, MPI_Fint *sendcount_FORTRAN, MPI_Fint *sendtype_FORTRAN,
		     char *recvbuf, MPI_Fint *recvcount_FORTRAN, MPI_Fint *recvtype_FORTRAN,
		     MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int type=type_allgather;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_ALLGATHER_FORTRAN fn=get_trace_type_fortran_fn(type);
    int sendcount = (*sendcount_FORTRAN);
    int recvcount = (*recvcount_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Datatype sendtype = PMPI_Type_f2c(*sendtype_FORTRAN);
    MPI_Datatype recvtype = PMPI_Type_f2c(*recvtype_FORTRAN);
    int ssize=0;
    int rsize=0;
    MPI_Type_size(sendtype,&ssize);
    MPI_Type_size(recvtype,&rsize);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&(log_threshold>recvcount*rsize||log_threshold>sendcount*ssize))){
        fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,comm_FORTRAN,ierr);
        return;
    } 
    start=timer_fn();
    fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=sendcount;
    log->sdatatype_size=ssize;
    log->rcount=recvcount;
    log->rdatatype_size=rsize;
    trace_index++;
    MT_UNLOCK()
}

// MPI_Allgatherv

void mpi_iallgather_(char *sendbuf, MPI_Fint *sendcount_FORTRAN, MPI_Fint *sendtype_FORTRAN,
                       char *recvbuf, MPI_Fint *recvcount_FORTRAN, MPI_Fint *recvtype_FORTRAN,
                       MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN, MPI_Fint *ierr){
    int type=type_iallgather;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_IALLGATHER_FORTRAN fn=get_trace_type_fortran_fn(type);
    int sendcount = (*sendcount_FORTRAN);
    int recvcount = (*recvcount_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    MPI_Datatype sendtype = PMPI_Type_f2c(*sendtype_FORTRAN);
    MPI_Datatype recvtype = PMPI_Type_f2c(*recvtype_FORTRAN);
    MPI_Request request;
    int ssize=0;
    int rsize=0;
    MPI_Type_size(sendtype,&ssize);
    MPI_Type_size(recvtype,&rsize);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&(log_threshold>recvcount*rsize||log_threshold>sendcount*ssize))){
        fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return;
    } 
    start=timer_fn();
    fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);  
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=sendcount;
    log->sdatatype_size=ssize;
    log->rcount=recvcount;
    log->rdatatype_size=rsize;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

// MPI_Iallgatherv

void mpi_scatter_(char *sendbuf, MPI_Fint *sendcount_FORTRAN,
		   MPI_Fint *sendtype_FORTRAN, char *recvbuf,
		   MPI_Fint *recvcount_FORTRAN, MPI_Fint *recvtype_FORTRAN,
		   MPI_Fint *root_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *ierr){
    int type=type_scatter;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_SCATTER_FORTRAN fn=get_trace_type_fortran_fn(type);
    int sendcount = (*sendcount_FORTRAN);
    int recvcount = (*recvcount_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int root = (*root_FORTRAN);
    MPI_Datatype sendtype = PMPI_Type_f2c(*sendtype_FORTRAN);
    MPI_Datatype recvtype = PMPI_Type_f2c(*recvtype_FORTRAN);
    int ssize=0;
    int rsize=0;
    MPI_Type_size(sendtype,&ssize);
    MPI_Type_size(recvtype,&rsize);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&(log_threshold>recvcount*rsize||log_threshold>sendcount*ssize))) {
        fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,root_FORTRAN,comm_FORTRAN,ierr);
        return;
    }
    start=timer_fn();
    fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,root_FORTRAN,comm_FORTRAN,ierr);
    end=timer_fn();
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,end);
    log->comm=comm;
    log->peer=root;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=sendcount;
    log->sdatatype_size=ssize;
    log->rcount=recvcount;
    log->rdatatype_size=rsize;
    trace_index++;
    MT_UNLOCK()     
}

// MPI_Scatterv

void mpi_iscatter_(char *sendbuf, MPI_Fint *sendcount_FORTRAN,
                     MPI_Fint *sendtype_FORTRAN, char *recvbuf,
                     MPI_Fint *recvcount_FORTRAN, MPI_Fint *recvtype_FORTRAN,
                     MPI_Fint *root_FORTRAN, MPI_Fint *comm_FORTRAN, MPI_Fint *request_FORTRAN,
                     MPI_Fint *ierr){
    int type=type_iscatter;
    int idx=-1;
    double start,end;
    trace_log_t* log;
    MPI_ISCATTER_FORTRAN fn=get_trace_type_fortran_fn(type);
    int sendcount = (*sendcount_FORTRAN);
    int recvcount = (*recvcount_FORTRAN);
    MPI_Comm comm = PMPI_Comm_f2c(*comm_FORTRAN);
    int root = (*root_FORTRAN);
    MPI_Datatype sendtype = PMPI_Type_f2c(*sendtype_FORTRAN);
    MPI_Datatype recvtype = PMPI_Type_f2c(*recvtype_FORTRAN);
    MPI_Request request;
    int ssize=0;
    int rsize=0;
    MPI_Type_size(sendtype,&ssize);
    MPI_Type_size(recvtype,&rsize);
    if((TRACE_IGNORE_LIST[type])||(log_threshold>0&&(log_threshold>recvcount*rsize||log_threshold>sendcount*ssize))){
        fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,root_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
        return;
    }  
    start=timer_fn();
    fn(sendbuf,sendcount_FORTRAN,sendtype_FORTRAN,recvbuf,recvcount_FORTRAN,recvtype_FORTRAN,root_FORTRAN,comm_FORTRAN,request_FORTRAN,ierr);
    end=timer_fn();
    request = PMPI_Request_f2c(*request_FORTRAN);
    MT_LOCK()
    idx=trace_index%max_trace_num;
    log=&probe_log[idx];
    new_log(log,type,trace_index,start,end,0);
    log->comm=comm;
    log->peer=root;
    log->gpeer=rank2global(log->peer,comm);
    log->scount=sendcount;
    log->sdatatype_size=ssize;
    log->rcount=recvcount;
    log->rdatatype_size=rsize;
    cache_request(&request,trace_index);
    trace_index++;
    MT_UNLOCK()
}

// MPI_Iscatterv
// MPI_Sendrecv
// MPI_Reduce_scatter